/**
 * 生成器
 * 
 */

//!getABC是生成器函数
function* getABC() {
    yield 'a';
    yield 'b';
    yield 'c';
}
function* gen(x){
  var y = yield x + 2; //g(1)---> {value:3, done:false}
  // var y = 2 + (yield x); //g(1)---> {value:1, done:false}
  return y;
}
function* func(x) {
  var y = x* (yield "hello") 
  return y
}
//!使用迭代器
var g = getABC();
for(const v of getABC()){
// for(const v of g){
  console.log(v);
}

/**
 *! g是生成器对象（可迭代对象/指针对象） [一般对象不可迭代]
 *? 所以生成器函数返回的是生成器对象 而不是return的结果
 * （1）可以用for/of; （2）可以用解构
 * g.next()返回一个对象{value: '下一个生成的值', done: false(是否执行完毕)} 直到 { value: undefined, done: true }
 * next()做到了将生成器分阶段执行
 */

var g1 = gen(1);
var g2 = func(6);
console.log(g1.next()); // { value: 3, done: false }
console.log(g1.next()); // { value: undefined, done: false }
 

/**
 * ! next()可以接受参数，向 Generator 函数体内输入数据
 */
console.log(g2.next(2)); //{ value: 'hello', done: false }
console.log(g2.next(3)); //参数会替代yield { value: 18, done: true }
console.log(g2.next());

/**
 *! 捕获函数体外抛出的错误
 * throw()
 使用指针对象的 throw 方法抛出的错误，可以被函数体内的 try ... catch 代码块捕获
 */
 function* genCatchError(x){
  try {
    var y = yield x + 2;
  } catch (e){ 
    console.log('捕获到错误：'+e);
  }
  return y;
}

var gen_catch_error = genCatchError(1);
console.log(gen_catch_error.next()) //{ value: 3, done: false }
gen_catch_error.throw('something wrong')

/**
 * ! return()方法
 * (1) return时执行到try外，return的参数作为返回值,结束生成器
 * (2) return时执行到try内，执行finally，return的参数作为返回值, 结束生成器
 */
function* genReturn() {
  // yield 1;
  // yield 2;
  // yield 3;
  try {
    yield 4;
  }catch(e){
    console.log(e)
  }finally{
    console.log('执行了finally')
  }
}
var gen_return = genReturn();
console.log(gen_return.next()); //{ value: 1, done: false }
console.log(gen_return.return('foo')); //{ value: 'foo', done: true }
console.log(gen_return.next()); //{ value: undefined, done: true }

/**
 *! yield* 语句 后面跟生成器, 会和当前生成器合并
 * 可以写递归写法
 */

function* sayName() {
  
  yield 'sun';
  yield 'yu';
  yield 'cui';
}
function* sayHello() {
  yield 'hello';
  yield* sayName(); //!yield*
  yield '!';
}
for(let v of sayHello()){
  console.log(v);
}
